package main

import (
	"fmt"
	"math"
	"time"
	"sync"
	"os"
	"os/exec"
	"io/ioutil")

func main() {
	exe("uname -a")
	exe("cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c")
	exe("free -h")
	exe("vmstat")
	
	fmt.Println("DOWNLOADING TEST DATA")

	f, err := os.Open("file")
	if err != nil && os.IsNotExist(err) {
		exe("wget http://mirrors.163.com/centos/7.5.1804/paas/x86_64/openshift-origin14/openvswitch-2.4.0-2.el7.x86_64.rpm -O file")
	} else {
		f.Close()
	}
	exe("ls -alh");
	
	bytes, err := ioutil.ReadFile("file")
	if err != nil {
		fmt.Println("download not saved")
		return
	}

	fmt.Println("TEST DATA READY")

	serial(bytes);
	parallel(bytes);
}

func serial(bytes []byte) {
	for aa := 0; aa < 3; aa++ {
		t := time.Now()

		m := make(map[uint]int)
		
		for i:= 0; i < len(bytes) - 2; i += 3 {
			var j uint = uint(bytes[i]) << 16 | uint(bytes[i + 1]) << 8 | uint(bytes[i + 2])

			if _, ok := m[j]; ok {
				m[j]++
			} else {
				m[j] = 1
			}
		}

		var result uint64 = 0
		for key, value := range m {
			result += uint64(key) * uint64(value)
		}

		s := time.Since(t)		//加权求和完成即截止计时
		fmt.Println("SERIAL:		", result, s)
	}
}

func parallel(bytes []byte) {
//	for aa := 0; aa < 3; aa++ {
		t := time.Now()

		m := make(map[uint]int)

		size := int(math.Floor(float64(len(bytes)) / 3.0))
		waitAll := make(chan bool, size)		//用于判断所有go routine结束的标志
		lock := new(sync.Mutex)

		for i:= 0; i < len(bytes) - 2; i += 3 {
			go func(x byte, y byte, z byte){
				var j uint = uint(x) << 16 | uint(y) << 8 | uint(z)

				lock.Lock()

				if _, ok := m[j]; ok {
					m[j]++
				}else{
					m[j]=1
				}

				lock.Unlock()
				waitAll <- false		//标志一个go routine完成
			}(bytes[i], bytes[i+1], bytes[i+2])
		}

		for i := 0; i < size; i++ { <- waitAll; }		//待所有go routine执行完才继续

		var result uint64 = 0
		for key,value := range m {
			result += uint64(key) * uint64(value);
		}

		s := time.Since(t)		//加权求和完成即截止计时
		fmt.Println("PARALLEL:	", result, s)
//	}
}

func exe(str string) {
	cmd := exec.Command("/bin/bash", "-c", str)
	stdout, _ := cmd.StdoutPipe()
   
  cmd.Start()
 
  bytes, _ := ioutil.ReadAll(stdout)
  
  cmd.Wait()
  fmt.Printf("%s\n", bytes)
}